#[macro_use]
extern crate log;
extern crate env_logger;

use std::net::UdpSocket;
use std::sync::mpsc::channel;
use sqlite::State;
use std::thread::spawn;
use std::time::UNIX_EPOCH;
use crate::geelogger::GeeLogger;
use protobuf::Message;

mod geelogger;
mod tool;

fn check_table_exist(connection: &sqlite::Connection, find_table_name: &str) -> bool {
    let mut statement = connection
        .prepare("SELECT name FROM sqlite_master WHERE name= ? ")
        .unwrap();
    statement.bind(1, find_table_name).unwrap();

    let mut isok = false;
    while let State::Row = statement.next().unwrap() {
        let table_name = statement.read::<String>(0).unwrap();
        // println!("name = {}", &table_name);
        isok = table_name.eq(find_table_name);
    };
    isok
}

fn creat_logger_table(connection: &sqlite::Connection, table_name: &str) {
    let result = connection.execute(format!("CREATE TABLE {} (
        time_at INTEGER ,
        client_time_at INTEGER ,
        logger_level INTEGER ,
        app_id INTEGER ,
        mod_type INTEGER ,
        sub_type INTEGER ,
        package_name TEXT,
        class_name TEXT,
        func_name TEXT,
        line_number INTEGER,
        msg TEXT
         );
        ", table_name));

    match result {
        Ok(_) => {
            info!("创建成功");
        }
        Err(err) => {
            error!("创建失败 {:?}", err);
        }
    }
}


fn add_logger_item_to_database(connection: &sqlite::Connection, data_info: GeeLogger) {
    let send_time = std::time::SystemTime::now();
    let since_the_epoch = send_time
        .duration_since(UNIX_EPOCH)
        .expect("Time went backwards");
    let timeat = since_the_epoch.as_secs() as i64 * 1000i64 + (since_the_epoch.subsec_nanos() as f64 / 1_000_000.0) as i64;
    let mut statement = connection
        .prepare(" INSERT INTO log_items (
            time_at,
            client_time_at,
            logger_level,
            app_id,
            mod_type,
            sub_type,
            package_name,
            class_name,
            func_name,
            line_number,
            msg
            ) VALUES (?,?,?,?,?,?,?,?,?,?,?); ")
        .unwrap();
    statement.bind(1, timeat).unwrap();
    statement.bind(2, data_info.get_client_time()).unwrap();
    statement.bind(3, data_info.get_logger_level() as i64).unwrap();
    statement.bind(4, data_info.get_app_id()).unwrap();
    statement.bind(5, data_info.get_mod_type()).unwrap();
    statement.bind(6, data_info.get_sub_type()).unwrap();
    statement.bind(7, data_info.get_package_name()).unwrap();
    statement.bind(8, data_info.get_class_name()).unwrap();
    statement.bind(9, data_info.get_func_name()).unwrap();
    statement.bind(10, data_info.get_line_number() as i64).unwrap();
    statement.bind(11, data_info.get_msg()).unwrap();
    let resule = statement.next();
    match resule {
        Ok(_) => {}
        Err(err) => {
            error!("data : {:?}" , data_info);
            error!("sava database fail : {:?}" ,err);
        }
    }

}


fn main() -> std::io::Result<()> {
    env_logger::init();
    // 增加线程池 处理
    let pool = tool::ThreadPool::new(8);
    debug!("GeeJoan logger tool start ... ");
    let socket = UdpSocket::bind("0.0.0.0:8080")?;
    let (log_tx, log_rx) = channel::<GeeLogger>();
    spawn(move || {
        // init db
        let connection = sqlite::open("log.db").unwrap();

        if !check_table_exist(&connection, "log_items") {
            // 表不存在
            // 创建
            creat_logger_table(&connection, "log_items");
        }

        // 这里开启 切换一下模式

        connection.execute("PRAGMA synchronous = OFF;").unwrap();

        for log_rx in log_rx.iter() {
            add_logger_item_to_database(&connection, log_rx);
        }
    });

    loop {
        let mut buffer = [0u8; 1500];
        // 一个数据包 长度 1460
        let (amt, src) = socket.recv_from(&mut buffer)?;
        if amt < 6 {
            // 太短了
            warn!("error : 数据包太短了, 忽略");
            continue;
        }
        let socket_client = socket.try_clone();
        let tx_client = log_tx.clone();
        pool.execute(move || {
            let socket = socket_client.unwrap();
            let log_tx = tx_client;
            let protodata = geelogger::GeeLogger::parse_from_bytes(&buffer[0..amt]);
            let data_info = match protodata {
                Ok(d) => { d }
                Err(err) => {
                    warn!("error : {:?} ", err);
                    return;
                }
            };
            if data_info.Gee != "Gee" {
                warn!("不支持的类型");
                let result = socket.send_to("nil".as_bytes(), &src);
                match result {
                    Ok(_) => {}
                    Err(err) => {
                        error!("回复失败 , {:?}", err);
                    }
                }
                return;
            }
            // TODO 校验密码
            // println!("data : {:?}", data_info.get_msg());
            // 存库
            let result = log_tx.send(data_info);
            match result {
                Ok(_) => {}
                Err(err) => {
                    error!("保存日志失败:{:?}", err);
                }
            }
            let result = socket.send_to("ok".as_bytes(), &src);
            match result {
                Ok(_) => {}
                Err(err) => {
                    error!("回复失败 , {:?}", err);
                }
            }
        });
    }
}